#pragma once
#include <exception>
#include <sstream>
#include <string>

class bounded_vector
{
private:
	int lowIndex;
	int highIndex;
	int *vptr;
	int size;

	void copy_from(const bounded_vector &that)
	{
		lowIndex = that.lowIndex;
		highIndex = that.highIndex;
		size = that.size;
		create_array(size);
		for (int i = 0; i < size; i++)
			vptr[i] = that.vptr[i];
	}

	void create_array(int size)
	{
		vptr = new int[size];
		for (int i = 0; i < size; i++)
			vptr[i] = 0;
	}

public:

	bounded_vector() : lowIndex(-1), highIndex(-1), vptr(nullptr), size(-1) { }

	bounded_vector(const int lowIndex, const int highIndex)
	{
		this->highIndex = highIndex;
		this->lowIndex = lowIndex;
		size = highIndex - lowIndex + 1;
		create_array(size);
	}

	bounded_vector(const bounded_vector &that)
	{
		copy_from(that);
	}

	bounded_vector& operator=(const bounded_vector &rop)
	{
		if (vptr != nullptr)
			delete[] vptr;
		copy_from(rop);
		return *this;
	}

	int& operator[](int i) { return vptr[i - lowIndex]; }

	friend bounded_vector operator+(const bounded_vector &lop, const bounded_vector &rop)
	{
		if (lop.size != rop.size || lop.lowIndex != rop.lowIndex || lop.highIndex != rop.highIndex)
			throw std::exception("Missmatched bounded_vector sizes or indices");
		bounded_vector bv(lop.lowIndex, lop.highIndex);
		for (int i = 0; i < bv.size; i++)
			bv.vptr[i] = lop.vptr[i] + rop.vptr[i];
		return bv;
	}

	~bounded_vector()
	{
		delete[] vptr;
	}

	void set_bounds(int lowIndex, int highIndex)
	{
		if (vptr != nullptr)
			delete[] vptr;
		this->highIndex = highIndex;
		this->lowIndex = lowIndex;
		size = highIndex - lowIndex + 1;
		create_array(size);
	}

	int total_sum()
	{
		int sum = 0;
		for (int i = 0; i < size; i++)
			sum += vptr[i];
		return sum;
	}

	std::string print()
	{
		std::ostringstream oss;
		for (int i = 0; i < size; i++)
		{
			oss << vptr[i];
			if (i + 1 < size)
				oss << ',';
		}
		return oss.str();
	}

	int get_size() { return size; }
	int get_lowIndex() { return lowIndex; }
	int get_highIndex() { return highIndex; }

	class iterator
	{
	public:
		typedef iterator self_type;
		typedef int value_type;
		typedef int* pointer;
		typedef int& reference;
		typedef std::forward_iterator_tag iterator_category;
		typedef int difference_type;

		iterator(pointer ptr_) { this->ptr_ = ptr_; }

		self_type operator++()
		{
			self_type i = *this;
			ptr_ = ptr_ + 1;
			return i;
		}

		self_type operator++(int junk)
		{
			ptr_ = ptr_ + 1;
			return *this;
		}

		bool operator==(const self_type& rop) { return ptr_ == rop.ptr_; }
		bool operator!=(const self_type& rop) { return ptr_ != rop.ptr_; }

		reference operator*() { return *ptr_; }
		pointer operator->() { return ptr_; }

	private:
		pointer ptr_;
	};

	iterator begin() { return iterator(vptr); }
	iterator end() { return iterator(vptr + size); }
};

